import axios from 'axios'
import { TokenUtil } from '/@/utils/TokenUtil.ts'
import { ElMessage, ElMessageBox } from 'element-plus'
import router from '/@/router/Router.ts'
import { Config } from '/@/config/Config.ts'
// 设置axios
const axiosInstance = axios.create({
  // 设置请求地址
  baseURL: import.meta.env.VITE_APP_SERVER_URL,
  // 允许跨域保存与携带cookie
  withCredentials: true,
})

// 忽略登录校验的请求地址列表
const ignoreLoginList = ['/sysUser/login', '/sysUser/register']

// 忽略响应拦截器的请求地址列表
const ignoreResponseList = ['']

/**
 * 未登录弹窗（注意，此函数的消息弹窗是异步的）
 */
const notLoginMessageBox = () => {
  ElMessageBox({
    type: 'warning',
    title: '警告',
    dangerouslyUseHTMLString: true,
    message:
      '<div>登录状态已失效，请重新登录</div>' +
      '<div style="color: var(--el-color-info)">注意：点击登录后当前页面未保存的数据将丢失</div>',
    showClose: true,
    showCancelButton: true,
    confirmButtonText: '登录',
    draggable: true,
  })
    .then(() =>
      router.push({
        name: 'Login',
      })
    )
    // 这个catch并非多余，若用户点击取消则后会调用。若不加这个catch，用户点击取消后控制台会报错
    .catch(() => {})
}

// 请求拦截
axiosInstance.interceptors.request.use(
  config => {
    if (config.url && ignoreLoginList.includes(config.url)) return config
    const token = TokenUtil.getToken()

    // 前端未找到token或token失效则认为用户未登录
    if (!token) {
      notLoginMessageBox()
      // 若前端判断其未登录，则立即停止请求，否则在响应拦截器登录判断中还会被拦截
      return Promise.reject(new Error('端未找到token或token失效。登录状态已失效。'))
    }
    return config
  },
  error => {
    console.log('请求拦截器报错', error)
    return Promise.reject(error)
  }
)

/**
 * 响应拦截器<br />
 * 对于拦截的请求，可以这样进行处理
 *
 * <pre>
 *   // 使用catch方式
 *   const login = async () => {
 *     stateIsLogging.value = true
 *     const { data } = await AuthApi.login(modelFormData.value).finally(() => (stateIsLogging.value = false))
 *     await RouterUtil.backToSourceRoute()
 *     console.log(data)
 *     stateIsLogging.value = false
 *   }
 *
 *   // 使用try finally方式
 *   const login = async () => {
 *     try {
 *       stateIsLogging.value = true
 *       const { data } = await AuthApi.login(modelFormData.value)
 *       await RouterUtil.backToSourceRoute()
 *       console.log(data)
 *     } finally {
 *       stateIsLogging.value = false
 *     }
 *   }
 * </pre>
 *
 * 若在请求后使用catch方式，则在拦截器中抛出的异常会被catch捕获，请求的后续代码会继续执行
 */
axiosInstance.interceptors.response.use(
  response => {
    if (response.config.url && ignoreResponseList.includes(response.config.url)) return response
    // 检查自定义状态吗（区别于协议的状态码，自定义状态码与其不同）
    switch (response.data.code) {
      case Config.statusCode.notLogin:
        // 若服务器返回未登录状态码，则认为用户未登录
        // TODO 此处还可以对用户下线原因进行处理
        notLoginMessageBox()
        console.error('登录状态已失效', response.data)
        return Promise.reject(new Error('服务器返回用户未登录。登录状态已失效。'))
      case Config.statusCode.parameterInvalid:
        ElMessage.error(response.data.message)
        console.error('请求参数无效', response.data)
        return Promise.reject(new Error('请求参数无效：' + response.data.message))
      case Config.statusCode.noPermission:
        ElMessage.error(response.data.message)
        console.error('无权限', response.data)
        return Promise.reject(new Error('无权限：' + response.data.message))
      case Config.statusCode.businessError:
        ElMessage.error(response.data.message)
        console.error('业务逻辑异常', response.data)
        return Promise.reject(new Error('业务逻辑异常：' + response.data.message))
      case Config.statusCode.unknownError:
        ElMessage.error(response.data.message)
        console.error('未知异常', response.data)
        return Promise.reject(new Error('未知异常：' + response.data.message))
    }
    return response
  },
  error => {
    // 此处为协议状态码错误处理
    console.log('响应拦截器报错', error)
    return Promise.reject(error)
  }
)

export default axiosInstance
